package com.tongji.housediy.utils
{
	//////////////////////////////////////by zazisb吸附判断
	import com.tongji.housediy.events.commonEvent.RelatedRoomAdminEvent;
	import com.tongji.housediy.view.components.AbstractBorderChild;
	import com.tongji.housediy.view.components.AbstractDrawingRoom;
	import com.tongji.housediy.view.components.GridContainer;
	import com.tongji.housediy.view.components.NormalDoor;
	import com.tongji.housediy.view.components.NormalWindow;
	import com.tongji.housediy.view.components.OpeningWall;
	import com.tongji.housediy.view.components.RoomBorder;
	import com.tongji.housediy.view.components.RoomShape;
	
	import de.polygonal.ds.DListNode;
	
	import flash.display.BlendMode;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class AbsorptionDetection
	{
		private static var roomIndexLowBorder:RoomBorder;
		private static var roomIndexHighBorder:RoomBorder;
		
		private static var indexLowPoint1:Point;
		private static var indexLowPoint2:Point;
		private static var indexHighPoint1:Point;
		private static var indexHighPoint2:Point;
		private static var exPt:Point;
		private static var tmpPoint:Point;
		
		private static var lowVector:Vector.<Number>;
		private static var highVector:Vector.<Number>;
		
		private static var gridContainer:GridContainer;
		private static var tmpOpenWall:OpeningWall;
		
		private static var judge:Boolean;
		
		public static function relatedAbsorptionObject(testRoom:AbstractDrawingRoom, collisionArray:Array):Array
		{
			var absorptionArray:Array = new Array();
			
			for(var i:int = 0; i < collisionArray.length; i++)// 遍历保存的和testRoom碰撞的AbstractDrawingRoom
			{
				var currentNode:DListNode = (collisionArray[i] as AbstractDrawingRoom).borderVertexList.head;//borderVertexList中的点保存为了循环链表的形式
				
				while (currentNode.next != (collisionArray[i] as AbstractDrawingRoom).borderVertexList.head)//遍历每个AbstractDrawingRoom中的边
				{
					currentNode = currentNode.next;
					
					if (currentNode.data is RoomBorder)
					{
						var currentTestRoomNode:DListNode = testRoom.borderVertexList.head;
						
						while (currentTestRoomNode.next != testRoom.borderVertexList.head)//遍历testRoom的边，上面遍历的边和testRoom的每条边比较
						{
							currentTestRoomNode = currentTestRoomNode.next;
							
							if (currentTestRoomNode.data is RoomBorder)
							{
								//判断是否2者碰撞
								if (CollisionDetection.complexHitTestObject((currentTestRoomNode.data as RoomBorder).drawShape, (currentNode.data as RoomBorder).drawShape))
								{
									var angle:Number = MathCalculation.getRoomBorderVectorAngle((currentTestRoomNode.data as RoomBorder).data[0], (currentTestRoomNode.data as RoomBorder).data[1],
										                                                        (currentTestRoomNode.data as RoomBorder).data[2], (currentTestRoomNode.data as RoomBorder).data[3],
																								(currentNode.data as RoomBorder).data[0], (currentNode.data as RoomBorder).data[1],
																								(currentNode.data as RoomBorder).data[2], (currentNode.data as RoomBorder).data[3]);
									if (Math.abs(Math.PI - angle) <= 0.0157) //判断斜率误差
									{
										var pair:Array = new Array();
										
										pair.push(currentTestRoomNode.data as RoomBorder);
										pair.push(currentNode.data as RoomBorder);
										absorptionArray.push(pair);   
									}
								}
							}
						}
					}		
				}
			}
			return absorptionArray;
		}
		
		public static function DoAbsorption(movedShape:RoomShape, special:Boolean = false, specialChild:AbstractBorderChild = null):void
		{
			/////////////////////////////by zazisb 保存碰撞关联的房间
			var collisionArray:Array = new Array();
			
			collisionArray = CollisionDetection.relatedCollisionObject(movedShape.parent as AbstractDrawingRoom);
			
			var relatedRoomVector:Vector.<AbstractDrawingRoom> = new Vector.<AbstractDrawingRoom>;
			
			if(collisionArray.length > 0)
			{
				var absorptionArray:Array = new Array();
				
				absorptionArray = relatedAbsorptionObject(movedShape.parent as AbstractDrawingRoom, collisionArray);
				
				if(absorptionArray.length > 0)//处理公共门窗
				{
					gridContainer = (movedShape.parent as AbstractDrawingRoom).parentGridContainer;
					
					for(var i:int = 0; i < absorptionArray.length; i++)
					{
						var hasOpenWall:Boolean = false;
						
						initVal(gridContainer, absorptionArray[i]);
						
						/////////////////////////////////////////////////////////////(记录index高的房间上公共部分的门）
						//记录共享边，在没有门但共享门的边上就能调用数据
						if(!special)
							roomIndexLowBorder.absorbRelatedBorder.push(roomIndexHighBorder);
						//遍历较高index的border上的child，找出所有在公共部分的abstractBorderchild
						var sharedChildArray:Array = GetSharedChildInBoundry(roomIndexHighBorder, highVector, indexLowPoint1, indexLowPoint2, indexHighPoint1, indexHighPoint2);
						
						if(sharedChildArray.length > 0)
						{
							for(var j:int = 0; j < sharedChildArray.length; j++)
							{
								if(!special)
									judge = true;
								else
								{
									if(sharedChildArray[j] == specialChild)
										judge = true;
									else
										judge = false;
								}
								
								if(judge)
								{
									//表示此孩子被共享
									sharedChildArray[j].shared = true;
									sharedChildArray[j].sharedBorder = roomIndexLowBorder;
									
									if(sharedChildArray[j] is OpeningWall)
									{
										//在低的index房间边上添加一个openwall使房间地板连接
										exPt = CalculateExPt(sharedChildArray[j], roomIndexLowBorder, lowVector);
										tmpPoint = MathCalculation.getOffsetValue(roomIndexLowBorder.k, sharedChildArray[j].length, roomIndexLowBorder.data);//解决门移动后的偏移
										
										exPt.x -= tmpPoint.x;
										exPt.y -= tmpPoint.y;
										
										tmpOpenWall = new OpeningWall(sharedChildArray[j].length);
										roomIndexLowBorder.addChild(tmpOpenWall);
										
										DealBorderChild(tmpOpenWall, roomIndexLowBorder, exPt);
										
										//设置标记取消吸附的时候用来删除
										tmpOpenWall.blendMode = BlendMode.ERASE;
										
										tmpOpenWall.fake = true;
										tmpOpenWall.sharedBorder = roomIndexHighBorder;
										tmpOpenWall.oppositeWall = sharedChildArray[j];
										sharedChildArray[j].oppositeWall = tmpOpenWall;
										//表示两个房间相连了
										hasOpenWall = true;
									}
									
									if(special)
										break;
								}
							}
						}
						/////////////////////////////////////////////////////////////(index低的房间上公共部分的门移动到index高的房间上的公共部分）
						//其中高index的点做垂足到低index的边上
						sharedChildArray = GetSharedChildInBoundry(roomIndexLowBorder, lowVector, indexHighPoint1, indexHighPoint2, indexLowPoint1, indexLowPoint2);
						
						if(sharedChildArray.length > 0)
						{
							for(var k:int = 0; k < sharedChildArray.length; k++)
							{
								if(!special)
									judge = true;
								else
								{
									if(sharedChildArray[k] == specialChild)
										judge = true;
									else
										judge = false;
								}
								
								if(judge)
								{
									if(sharedChildArray[k] is NormalDoor || sharedChildArray[k] is NormalWindow || (sharedChildArray[k] is OpeningWall && (sharedChildArray[k].fake == false)))
									{
										//表示此门被共享
										sharedChildArray[k].borrowed = true;
										sharedChildArray[k].sharedBorder = roomIndexLowBorder;
										
										exPt = CalculateExPt(sharedChildArray[k], roomIndexHighBorder, highVector);
										//remove低index上的Borderchild
										roomIndexLowBorder.removeChild(sharedChildArray[k]);
										
										//如果是开放墙原墙先复制一个再把原墙出借
										if(sharedChildArray[k] is OpeningWall)
										{
											tmpOpenWall = new OpeningWall(sharedChildArray[k].length);
											roomIndexLowBorder.addChild(tmpOpenWall);
											
											DealBorderChild(tmpOpenWall, roomIndexLowBorder, new Point(sharedChildArray[k].data[0], sharedChildArray[k].data[1]));
											
											tmpOpenWall.blendMode = BlendMode.ERASE;
											
											tmpOpenWall.fake = true;
											tmpOpenWall.sharedBorder = roomIndexHighBorder;
										}
										
										//在高index的边上加上Borderchild
										tmpPoint = MathCalculation.getOffsetValue(roomIndexHighBorder.k, sharedChildArray[k].length, roomIndexHighBorder.data);//解决门移动后的偏移
										
										exPt.x -= tmpPoint.x;
										exPt.y -= tmpPoint.y
										
										roomIndexHighBorder.addChild(sharedChildArray[k]);
										
										DealBorderChild(sharedChildArray[k], roomIndexHighBorder, exPt);
										
										if(sharedChildArray[k] is NormalDoor)
										{
											var revRotate:Number = sharedChildArray[k].getReverseRotation(sharedChildArray[k].data, roomIndexHighBorder.k);
											//转换相应的门状态
											sharedChildArray[k].rotateState += 2;
											
											if(sharedChildArray[k].rotateState == 5)
												sharedChildArray[k].rotateState = 1;
											else if(sharedChildArray[k].rotateState == 6)
												sharedChildArray[k].rotateState = 2;
											
											sharedChildArray[k].transformNormalDoorState(tmpPoint, revRotate, sharedChildArray[k].rotateState);
										}	
										else if(sharedChildArray[k] is OpeningWall)
										{
											sharedChildArray[k].blendMode = BlendMode.ERASE;
											tmpOpenWall.oppositeWall = sharedChildArray[k];
											sharedChildArray[k].oppositeWall = tmpOpenWall;
											hasOpenWall = true;
										}
									}
									
									if(special)
										break;
								}
							}
						}
						
						if(hasOpenWall)
						{
							if(roomIndexLowBorder.parent as AbstractDrawingRoom == movedShape.parent as AbstractDrawingRoom)
								relatedRoomVector.push(roomIndexHighBorder.parent as AbstractDrawingRoom);
							else
								relatedRoomVector.push(roomIndexLowBorder.parent as AbstractDrawingRoom);
						}
					}
					
				}
			}

			movedShape.dispatchEvent(new RelatedRoomAdminEvent(RelatedRoomAdminEvent.UPDATE_RELATED_ROOM, movedShape.parent as AbstractDrawingRoom, relatedRoomVector));
		}
		
		public static function CancelAbsorption(movedShape:RoomShape):void
		{
			////////////////////////////////////////////////////by zazisb 取消吸附时的共享等记录，转换回原样
			var collisionArray:Array = new Array();
			
			collisionArray = CollisionDetection.relatedCollisionObject(movedShape.parent as AbstractDrawingRoom);
			
			if(collisionArray.length > 0)
			{
				var absorptionArray:Array = new Array();
				
				absorptionArray = AbsorptionDetection.relatedAbsorptionObject(movedShape.parent as AbstractDrawingRoom, collisionArray);
				
				if(absorptionArray.length > 0)//处理公共门窗
				{
					gridContainer = (movedShape.parent as AbstractDrawingRoom).parentGridContainer;
				
					for(var i:int = 0; i < absorptionArray.length; i++)
					{
						initVal(gridContainer, absorptionArray[i]);
						
						if(roomIndexLowBorder.absorbRelatedBorder.length > 0)
						{
							//去除两条边的关联
							for(var j:int = 0; j < roomIndexLowBorder.absorbRelatedBorder.length; j++)
							{
								if(roomIndexLowBorder.absorbRelatedBorder[j] == roomIndexHighBorder)
								{
									roomIndexLowBorder.absorbRelatedBorder.splice(j, 1);
									break;
								}
							}
							//////////////////(还原index高的房间上属性为shared的child并且删除低 index房间上属性为fake的openwall）
							roomIndexHighBorder.recoveSharedChild(roomIndexLowBorder);
							roomIndexLowBorder.removeFakeChild(roomIndexHighBorder);
							//////////////////(将index高的房间上属性为borrowed的child还给低 index房间）
							var borrowedChildArray:Array = new Array();
							
							borrowedChildArray = roomIndexHighBorder.findChildBorrowed(roomIndexLowBorder);
							
							if(borrowedChildArray.length > 0)
							{
								for(var k:int = 0; k < borrowedChildArray.length; k++)
								{
									if(borrowedChildArray[k] is NormalDoor || borrowedChildArray[k] is NormalWindow || borrowedChildArray[k] is OpeningWall)
									{
										//取消属性
										borrowedChildArray[k].borrowed = false;
										
										exPt = CalculateExPt(borrowedChildArray[k], roomIndexLowBorder, lowVector);
										
										//remove高index上的Borderchild
										roomIndexHighBorder.removeChild(borrowedChildArray[k]);
										
										//在低index的边上加上Borderchild
										tmpPoint = MathCalculation.getOffsetValue(roomIndexLowBorder.k, borrowedChildArray[k].length, roomIndexLowBorder.data);//解决门移动后的偏移
										
										exPt.x -= tmpPoint.x;
										exPt.y -= tmpPoint.y
										
										roomIndexLowBorder.addChild(borrowedChildArray[k]);
										
										DealBorderChild(borrowedChildArray[k], roomIndexLowBorder, exPt);
						
										if(borrowedChildArray[k] is NormalDoor)
										{
											var revRotate:Number = borrowedChildArray[k].getReverseRotation(borrowedChildArray[k].data, roomIndexLowBorder.k);
											//转换相应的门状态
											borrowedChildArray[k].rotateState += 2;
											
											if(borrowedChildArray[k].rotateState == 5)
												borrowedChildArray[k].rotateState = 1;
											else if(borrowedChildArray[k].rotateState == 6)
												borrowedChildArray[k].rotateState = 2;
											
											borrowedChildArray[k].transformNormalDoorState(tmpPoint, revRotate, borrowedChildArray[k].rotateState);
										}	
										if(borrowedChildArray[k] is OpeningWall)
											(borrowedChildArray[k] as OpeningWall).oppositeWall = null;
									}
								}
							}
						}
					}
				}
			}
		}
		
		public static function DeleteRelateOpenWall(openWall:OpeningWall):void
		{
			var oppositeWall:OpeningWall = openWall.oppositeWall;
			var oppositeBorder:RoomBorder = openWall.sharedBorder;
			
			if(oppositeWall != null)
			{
				openWall.oppositeWall = null;
				openWall.fake = false;
				oppositeWall.oppositeWall = null;
				
				oppositeBorder.removeChild(oppositeWall);
			}
		}
		
		/**
		 * 初始化成员变量 
		 * @param grid
		 * @param absorptionArray
		 * 
		 */		
		private static function initVal(grid:GridContainer, absorptionArray:Array):void
		{
			if(grid.getChildIndex(absorptionArray[0].parent as AbstractDrawingRoom) >=
				grid.getChildIndex(absorptionArray[1].parent as AbstractDrawingRoom))// 判断高低index
			{
				roomIndexLowBorder = absorptionArray[1];
				roomIndexHighBorder = absorptionArray[0];
			}
			else
			{
				roomIndexLowBorder = absorptionArray[0];
				roomIndexHighBorder = absorptionArray[1];
			}			
			//转换4个点的坐标为网格坐标
			indexLowPoint1 = MathCalculation.transExPtFromInPt(roomIndexLowBorder, new Point(roomIndexLowBorder.data[0], roomIndexLowBorder.data[1]));
			indexLowPoint2 = MathCalculation.transExPtFromInPt(roomIndexLowBorder, new Point(roomIndexLowBorder.data[2], roomIndexLowBorder.data[3]));
			
			lowVector = new Vector.<Number>;
			
			lowVector.push(indexLowPoint1.x);
			lowVector.push(indexLowPoint1.y);
			lowVector.push(indexLowPoint2.x);
			lowVector.push(indexLowPoint2.y);
			
			indexHighPoint1 = MathCalculation.transExPtFromInPt(roomIndexHighBorder, new Point(roomIndexHighBorder.data[0], roomIndexHighBorder.data[1]));
			indexHighPoint2 = MathCalculation.transExPtFromInPt(roomIndexHighBorder, new Point(roomIndexHighBorder.data[2], roomIndexHighBorder.data[3]));
			
			highVector = new Vector.<Number>;
			
			highVector.push(indexHighPoint1.x);
			highVector.push(indexHighPoint1.y);
			highVector.push(indexHighPoint2.x);
			highVector.push(indexHighPoint2.y);
		}
		/**
		 * 获取公共区域的共享child 
		 * @param targetBorder 被做垂足的边
		 * @param targetVec 被做垂足边得data vector
		 * @param movPoint1 做垂足边的两个顶点
		 * @param movPoint2
		 * @param targetPoint1 被做垂足边得两个顶点
		 * @param targetPoint2
		 * @return  返回孩子列表
		 * 
		 */		
		private static function GetSharedChildInBoundry(targetBorder:RoomBorder, targetVec:Vector.<Number>,
												 movPoint1:Point, movPoint2:Point, targetPoint1:Point, targetPoint2:Point):Array
		{
			//moveBorder上的点做垂足到targetBorder上
			var moveToTargetPoint1:Point = MathCalculation.getPedalPoint(targetBorder.k, targetVec, new Point(movPoint1.x, movPoint1.y));
			var moveToTargetPoint2:Point = MathCalculation.getPedalPoint(targetBorder.k, targetVec, new Point(movPoint2.x, movPoint2.y));
			
			//求公共部分的两个点(在targetBorder上）
			var twoPtArray:Array = MathCalculation.getTwoPtInFourPt(targetPoint1, targetPoint2, moveToTargetPoint1, moveToTargetPoint2);
			
			//计算两点形成的范围
			var boundry:Rectangle;
			
			boundry = MathCalculation.getRectangleByTwoPoint(twoPtArray[0].x, twoPtArray[0].y, twoPtArray[1].x, twoPtArray[1].y);
			//遍历targetBorder上的child，找出所有在公共部分的abstractBorderchild
			return targetBorder.findChildInBoundry(boundry);
		}
		/**
		 * 将child的想x,y坐标算出并将它们从外部坐标转换为内部的 
		 * @param borderChild 
		 * @param targetBorder 加在那条边
		 * @param targetVec 那条边的data vector
		 * @return 返回坐标
		 * 
		 */		
		private static function CalculateExPt(borderChild:AbstractBorderChild, targetBorder:RoomBorder, targetVec:Vector.<Number>):Point
		{
			//要移动孩子边上的child做垂足到target边上
			var movChildPoint:Point = MathCalculation.transExPtFromInPt(borderChild, new Point(borderChild.data[0], borderChild.data[1]));
			var moveToTargetPoint:Point = MathCalculation.getPedalPoint(targetBorder.k, targetVec, new Point(movChildPoint.x, movChildPoint.y));
			
			//将它们转换成target边上的坐标
			return MathCalculation.transInPtFromExPt(targetBorder, moveToTargetPoint);
		}
		/**
		 * 处理child 
		 * @param dealChild 被处理的child
		 * @param targetBorder  child在那条边上
		 * @param exPt   child的x,y值（房间坐标系）
		 * 
		 */		
		private static function DealBorderChild(dealChild:AbstractBorderChild, targetBorder:RoomBorder, exPt:Point):void
		{
			dealChild.parentBorder = targetBorder;
			
			dealChild.x = exPt.x;
			dealChild.y = exPt.y;
			
			dealChild.setRotation(targetBorder.data, targetBorder.k, exPt);
			dealChild.percentPosition = Math.sqrt((exPt.x - targetBorder.data[0])  
				* (exPt.x - targetBorder.data[0]) + (exPt.y - targetBorder.data[1]) * (exPt.y - targetBorder.data[1]))
				/ Math.sqrt((targetBorder.data[2] - targetBorder.data[0]) * (targetBorder.data[2] - targetBorder.data[0])
					+ (targetBorder.data[3] - targetBorder.data[1]) * (targetBorder.data[3] - targetBorder.data[1]));
			
			targetBorder.changeChildIndex(dealChild);
		}
	}
}